#include "tabview.h"
#include "log.h"
#include "system.h"

#include "stack.h"
#include "list.h"
#include "animation.h"

#include <string.h>
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlmemory.h>

typedef struct _TABVIEWITEMDATA
{
	UFO_View view;
	int index;
	UFO_Animation animation;
}TABVIEWITEMDATA;

typedef struct _TABVIEW
{
	float itemSize;
	UFO_List itemList;
	TABVIEWITEMDATA *currentItem;
	ufoRect  touch_rect;
}TABVIEW;

int ufoTabViewSetOrientation(UFO_View view, int orientation)
{
	return 0;
}

int ufoTabViewSetItemRect(UFO_View view, ufoRect *itemRect)
{
	return 0;
}

TABVIEWITEMDATA* internal_tabview_getitemdata(UFO_View view, int index)
{
	TABVIEW *pTabView = (TABVIEW*)ufoViewGetUserData(view);
	if (pTabView) {
		UFO_List_Iteartor it = ufoListBegin(pTabView->itemList);
		while (it) {
			TABVIEWITEMDATA *itemData = (TABVIEWITEMDATA*)ufoListGetElement(it);
			if (itemData && itemData->index == index) {
				return itemData;
			}
			it = ufoListIteartorForward(it);
		}
	}
	return 0;
}

void internal_tabview_adjust(UFO_View view, int bTouch)
{
	TABVIEW *pTabView = (TABVIEW*)ufoViewGetUserData(view);
	if (pTabView && pTabView->currentItem) {
		if (bTouch) {	//### ufoGetTouchState()
			TABVIEWITEMDATA *currentItem = pTabView->currentItem;
			UFO_View subView = currentItem->view;
			ufoRect subRect = {0};
			int newIndex = 0;
			ufoViewGetRect(subView, &subRect);

			subRect.top += pTabView->itemSize/2;
			newIndex = (int)(subRect.top/pTabView->itemSize);
			if (newIndex >= ufoViewGetChildCount(view))
				newIndex = ufoViewGetChildCount(view)-1;

			if (newIndex < 0) {
				newIndex = 0;
			}

			if (newIndex < currentItem->index) {
				int i;
				TABVIEWITEMDATA* itemDataArr[500];//### hard code for 1000 items
				for (i = newIndex; i < currentItem->index; ++i) {//### move rect by animation
					TABVIEWITEMDATA *pItemData = internal_tabview_getitemdata(view, i);
					itemDataArr[i] = pItemData;
					if (pItemData) {
						UFO_Animation_Value value = {Animation_rect};

						ufoViewGetRect(pItemData->view, &value.rect);
						value.rect.top = (i+1)*pTabView->itemSize;
						value.rect.bottom = (i+2)*pTabView->itemSize;

						ufoAnimationStop(pItemData->animation);
						ufoAnimationSetToValue(pItemData->animation, value);
                        ufoAnimationSetDuration(pItemData->animation, 300);
						ufoAnimationSetTimingFunction(pItemData->animation, TimingFunctionEaseInEaseOut);
						ufoAnimationPlay(pItemData->animation);
						//ufoViewSetRect(pItemData->view, &value.rect);
					}
				}

				for (i = newIndex; i < currentItem->index; ++i) {//### update index
					TABVIEWITEMDATA *pItemData = itemDataArr[i];
					if (pItemData) {
						pItemData->index++;
					}
				}
				currentItem->index = newIndex;
			}
			else if (newIndex > currentItem->index) {
				int i;
				TABVIEWITEMDATA* itemDataArr[500];//### hard code for 1000 items
				for (i = currentItem->index+1; i <= newIndex; ++i) {//### move rect by animation
					TABVIEWITEMDATA *pItemData = internal_tabview_getitemdata(view, i);
					itemDataArr[i] = pItemData;
					if (pItemData) {
						UFO_Animation_Value value = {Animation_rect};
						ufoViewGetRect(pItemData->view, &value.rect);

						value.rect.top = (i-1)*pTabView->itemSize;
						value.rect.bottom = (i)*pTabView->itemSize;

						ufoAnimationStop(pItemData->animation);
						ufoAnimationSetToValue(pItemData->animation, value);
                        ufoAnimationSetDuration(pItemData->animation, 300);
						ufoAnimationSetTimingFunction(pItemData->animation, TimingFunctionEaseInEaseOut);
						ufoAnimationPlay(pItemData->animation);
						//ufoViewSetRect(pItemData->view, &value.rect);
					}
				}

				for (i = currentItem->index+1; i <= newIndex; ++i) {//### update index
					TABVIEWITEMDATA *pItemData = itemDataArr[i];
					if (pItemData) {
						pItemData->index--;
					}
				}
				currentItem->index = newIndex;
			}
		}
		else {
			UFO_Animation_Value value = {Animation_rect};
			ufoRect rect = {0};

			ufoViewGetRect(pTabView->currentItem->view, &rect);
			value.rect = rect;
			value.rect.top = (pTabView->currentItem->index)*pTabView->itemSize;
			value.rect.bottom = (pTabView->currentItem->index+1)*pTabView->itemSize;

			if (ufoRectEqual(&rect, &value.rect)) {
				ufoAnimationSetDuration(pTabView->currentItem->animation, 1);
			}
			else {
				ufoAnimationSetDuration(pTabView->currentItem->animation, 300);
			}

			ufoAnimationStop(pTabView->currentItem->animation);
			ufoAnimationSetToValue(pTabView->currentItem->animation, value);		
			ufoAnimationSetTimingFunction(pTabView->currentItem->animation, TimingFunctionEaseInEaseOut);
			ufoAnimationPlay(pTabView->currentItem->animation);
		}
	}
}

int default_tabview_proc(UFO_View view, int id, void* wParam, void* lParam)
{
	TABVIEW *pTabView = (TABVIEW*)ufoViewGetUserData(view);
	if (!pTabView) {
		pTabView = (TABVIEW*)malloc(sizeof(TABVIEW));
		memset(pTabView, 0, sizeof(TABVIEW));
		ufoViewSetUserData(view, pTabView);

		//### hard code
		pTabView->itemSize = 40;
		pTabView->itemList = ufoListCreate(sizeof(TABVIEWITEMDATA));
	}
	switch (id)
	{
	case MSG_SIZE_CHANGE:
		{
			ufoRect *rect = (ufoRect*)wParam;
			float y = 0;
			UFO_View subView = ufoViewGetChild(view);
			ufoRectOffset(rect, -rect->left, -rect->top);
			while (subView) {
				ufoRect subRect = {rect->left, y, rect->right, y+pTabView->itemSize};
				y += pTabView->itemSize;
				ufoViewSetRect(subView, &subRect);
				subView = ufoViewGetNextView(subView);
			}
		}
		break;

	case MSG_ADD_CHILDVIEW:
		{
			TABVIEWITEMDATA *pData = (TABVIEWITEMDATA *)malloc(sizeof(TABVIEWITEMDATA));
			memset(pData, 0, sizeof(TABVIEWITEMDATA));
			pData->view = (UFO_View)wParam;
			pData->animation = ufoAnimationCreate(pData->view);
			pData->index = ufoViewGetChildCount(view)-1;

			ufoListPushBack(pTabView->itemList, pData);
		}
		break;

	case MSG_CREATE:
		{
            ufoViewSetGesture(view, GESTURE_PAN);
		}
		break;

	case MSG_TOUCH_DOWN:
		{
			ufoPoint *pt = (ufoPoint*)wParam;
			UFO_List_Iteartor it = ufoListBegin(pTabView->itemList);
			while (it) {
				TABVIEWITEMDATA *itemData = (TABVIEWITEMDATA*)ufoListGetElement(it);
				if (itemData) {
					ufoRect rect = {0};
					ufoViewGetRect(itemData->view, &rect);
					if (ufoRectIsPointIn(&rect, pt->x, pt->y)) {
						float zOrder = ufoViewGetZorder(itemData->view);
						if (!pTabView->currentItem ||
							(pTabView->currentItem && ufoViewGetZorder(pTabView->currentItem->view) < zOrder)) {
								ufoViewGetRect(itemData->view, &pTabView->touch_rect);						
								pTabView->currentItem = itemData;
						}
					}
				}
				it = ufoListIteartorForward(it);
			}
			if (pTabView->currentItem) {
				ufoViewSetZorder(pTabView->currentItem->view, -1.0f);
			}
		}
		break;

	case MSG_TOUCH_UP:
		{
			internal_tabview_adjust(view, 0);
			if (pTabView->currentItem) {
				ufoViewSetZorder(pTabView->currentItem->view, 0.0f);
			}
			pTabView->currentItem = 0;
		}
		break;

	case MSG_GESTURE_PAN:
		{
			if (pTabView->currentItem) {
                ufoPoint *delta = (ufoPoint*)wParam;
				ufoRect rect = {0};
                ufoRect currentRect = {0};
                
                ufoViewGetRect(view, &currentRect);
				ufoViewGetRect(pTabView->currentItem->view, &rect);
				ufoRectMoveTo(&rect, 0, pTabView->touch_rect.top + (delta->y));
				
                ufoRectOffset(&currentRect, -currentRect.left, -currentRect.top);
                
                if (rect.top + pTabView->itemSize/2 > currentRect.bottom) {
                    rect.top = currentRect.bottom - pTabView->itemSize/2;
                    rect.bottom = rect.top + pTabView->itemSize;
                }
                
                if (rect.top < -pTabView->itemSize/2) {
                    rect.top = -pTabView->itemSize/2;
                    rect.bottom = rect.top + pTabView->itemSize;
                }
                
                ufoViewSetRect(pTabView->currentItem->view, &rect);

				internal_tabview_adjust(view, 1);
			}
		}
		break;
	}
	return ufoViewDefaultProc(view, id, wParam, lParam);//### pass to default view proc
}

